package org.eiahe.hr.salary.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ehe.common.core.utils.MapstructUtils;
import org.ehe.common.core.utils.StringUtils;
import org.ehe.common.mybatis.core.page.PageQuery;
import org.ehe.common.mybatis.core.page.TableDataInfo;
import org.ehe.system.service.ISysDeptService;
import org.springframework.stereotype.Service;
import org.eiahe.hr.salary.domain.BonusPayment;
import org.eiahe.hr.salary.domain.BonusCalculation;
import org.eiahe.hr.salary.domain.bo.BonusPaymentBo;
import org.eiahe.hr.salary.domain.vo.BonusPaymentVo;
import org.eiahe.hr.salary.domain.vo.BonusImportVo;
import org.eiahe.hr.salary.mapper.BonusPaymentMapper;
import org.eiahe.hr.salary.mapper.BonusCalculationMapper;
import org.eiahe.hr.salary.service.IBonusPaymentService;
import org.ehe.common.core.utils.SpringUtils;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;

/**
 * 奖金发放Service业务层处理
 *
 * @author zhangnn
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class BonusPaymentServiceImpl implements IBonusPaymentService {

    private final BonusPaymentMapper baseMapper;

    /**
     * 查询奖金发放
     *
     * @param paymentId 奖金发放ID
     * @return 奖金发放
     */
    @Override
    public BonusPaymentVo queryById(Long paymentId) {
        return baseMapper.selectVoById(paymentId);
    }

    /**
     * 查询奖金发放列表
     *
     * @param bo 奖金发放业务对象
     * @return 奖金发放集合
     */
    @Override
    public List<BonusPaymentVo> queryList(BonusPaymentBo bo) {
        LambdaQueryWrapper<BonusPayment> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    /**
     * 分页查询奖金发放列表
     *
     * @param bo        奖金发放业务对象
     * @param pageQuery 分页参数
     * @return 奖金发放分页数据
     */
    @Override
    public TableDataInfo<BonusPaymentVo> queryPageList(BonusPaymentBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<BonusPayment> lqw = buildQueryWrapper(bo);
        Page<BonusPaymentVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 新增奖金发放
     *
     * @param bo 奖金发放业务对象
     * @return 是否成功
     */
    @Override
    public Boolean insertByBo(BonusPaymentBo bo) {
        BonusPayment add = MapstructUtils.convert(bo, BonusPayment.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setPaymentId(add.getPaymentId());
            // 同时创建核算记录
            createBonusCalculation(add);
        }
        return flag;
    }

    /**
     * 修改奖金发放
     *
     * @param bo 奖金发放业务对象
     * @return 是否成功
     */
    @Override
    public Boolean updateByBo(BonusPaymentBo bo) {
        BonusPayment update = MapstructUtils.convert(bo, BonusPayment.class);
        validEntityBeforeSave(update);
        boolean flag = baseMapper.updateById(update) > 0;
        if (flag) {
            // 同时更新核算记录
            updateBonusCalculation(update);
        }
        return flag;
    }

    /**
     * 批量删除奖金发放
     *
     * @param ids 奖金发放ID数组
     * @return 是否成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids) {
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 发放奖金
     *
     * @param paymentId 奖金发放ID
     * @return 是否成功
     */
    @Override
    public Boolean payBonus(Long paymentId) {
        BonusPayment payment = baseMapper.selectById(paymentId);
        if (payment == null) {
            log.warn("奖金发放记录不存在，paymentId: {}", paymentId);
            return false;
        }

        // 校验状态：检查对应的核算记录是否已审核
        if (!isCalculationApproved(payment.getEmployeeNo(), payment.getBonusType())) {
            log.warn("对应的奖金核算记录未审核，不能发放奖金");
            throw new RuntimeException("对应的奖金核算记录未审核，不能发放奖金");
        }

        // 更新发放状态为已发放
        payment.setPaymentStatus("1");
        boolean result = baseMapper.updateById(payment) > 0;

        if (result) {
            // 同时更新核算记录状态为已发放
            updateCalculationStatus(payment.getEmployeeNo(), payment.getBonusType(), "2");
        }

        return result;
    }

    /**
     * 检查奖金核算记录是否已审核
     *
     * @param employeeNo 工号
     * @param bonusType  奖金类型
     * @return 是否已审核
     */
    private boolean isCalculationApproved(String employeeNo, String bonusType) {
        try {
            BonusCalculationMapper calculationMapper = SpringUtils.getBean(BonusCalculationMapper.class);

            LambdaQueryWrapper<BonusCalculation> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(BonusCalculation::getEmployeeNo, employeeNo);
            queryWrapper.eq(BonusCalculation::getBonusType, bonusType);

            BonusCalculation calculation = calculationMapper.selectOne(queryWrapper);
            // 如果核算记录不存在或者状态不是已审核，则返回false
            return calculation != null && "1".equals(calculation.getCalculationStatus());
        } catch (Exception e) {
            log.error("检查奖金核算记录状态失败，employeeNo: {}, bonusType: {}", employeeNo, bonusType, e);
            return false;
        }
    }

    /**
     * 领取奖金
     *
     * @param paymentId 奖金发放ID
     * @return 是否成功
     */
    @Override
    public Boolean receiveBonus(Long paymentId) {
        BonusPayment payment = baseMapper.selectById(paymentId);
        if (payment == null) {
            log.warn("奖金发放记录不存在，paymentId: {}", paymentId);
            return false;
        }

        // 更新领取状态为已领取
        payment.setReceiveStatus("1");
        boolean result = baseMapper.updateById(payment) > 0;

        // 可以根据业务需求决定是否需要更新核算记录状态
        // 这里暂时不更新，因为核算记录主要关注发放状态

        return result;
    }

    /**
     * 导入奖金数据
     *
     * @param dataList  数据列表
     * @param errorList 错误信息列表
     * @return 是否成功
     */
    @Override
    public Boolean importBonusData(List<BonusImportVo> dataList, List<String> errorList) {
        int successCount = 0;
        for (int i = 0; i < dataList.size(); i++) {
            BonusImportVo importVo = dataList.get(i);
            try {
                // 数据校验
                if (!validImportData(importVo)) {
                    errorList.add("第" + (i + 1) + "行数据校验失败");
                    continue;
                }

                // 转换为实体对象
                BonusPayment entity = MapstructUtils.convert(importVo, BonusPayment.class);

                // 设置默认状态
                entity.setPaymentStatus("0"); // 未发放
                entity.setReceiveStatus("0"); // 未领取

                // 保存奖金发放数据
                baseMapper.insert(entity);

                // 同时创建核算记录
                createBonusCalculation(entity);

                successCount++;
            } catch (Exception e) {
                log.error("导入第{}行数据失败", i + 1, e);
                errorList.add("第" + (i + 1) + "行数据导入失败: " + e.getMessage());
            }
        }

        log.info("奖金数据导入完成，成功{}条，失败{}条", successCount, errorList.size());
        return true;
    }

    /**
     * 创建奖金核算记录
     *
     * @param bonusPayment 奖金发放实体
     */
    private void createBonusCalculation(BonusPayment bonusPayment) {
        try {
            BonusCalculationMapper calculationMapper = SpringUtils.getBean(BonusCalculationMapper.class);

            // 检查是否已存在相同的核算记录
            LambdaQueryWrapper<BonusCalculation> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(BonusCalculation::getEmployeeNo, bonusPayment.getEmployeeNo());
            queryWrapper.eq(BonusCalculation::getBonusType, bonusPayment.getBonusType());

            BonusCalculation existingCalculation = calculationMapper.selectOne(queryWrapper);

            if (existingCalculation == null) {
                // 不存在则创建新的核算记录
                BonusCalculation calculation = new BonusCalculation();
                calculation.setTenantId(bonusPayment.getTenantId());
                calculation.setEmployeeNo(bonusPayment.getEmployeeNo());
                calculation.setEmployeeName(getEmployeeNameByNo(bonusPayment.getEmployeeNo()));
                calculation.setBonusType(bonusPayment.getBonusType());
                calculation.setBonusAmount(bonusPayment.getBonusAmount());
                calculation.setCalculationRule(bonusPayment.getCalculationRule());
                calculation.setCalculator(bonusPayment.getCalculator());
                calculation.setCalculationTime(bonusPayment.getCalculationTime());
                calculation.setCalculationStatus("0"); // 待审核状态

                calculationMapper.insert(calculation);
            } else {
                // 存在则更新核算记录
                existingCalculation.setBonusAmount(bonusPayment.getBonusAmount());
                existingCalculation.setCalculationRule(bonusPayment.getCalculationRule());
                existingCalculation.setCalculator(bonusPayment.getCalculator());
                existingCalculation.setCalculationTime(bonusPayment.getCalculationTime());

                calculationMapper.updateById(existingCalculation);
            }
        } catch (Exception e) {
            log.error("创建/更新奖金核算记录失败，paymentId: {}", bonusPayment.getPaymentId(), e);
        }
    }

    /**
     * 更新奖金核算记录
     *
     * @param bonusPayment 奖金发放实体
     */
    private void updateBonusCalculation(BonusPayment bonusPayment) {
        try {
            BonusCalculationMapper calculationMapper = SpringUtils.getBean(BonusCalculationMapper.class);

            // 根据工号和奖金类型查找对应的核算记录
            LambdaQueryWrapper<BonusCalculation> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(BonusCalculation::getEmployeeNo, bonusPayment.getEmployeeNo());
            queryWrapper.eq(BonusCalculation::getBonusType, bonusPayment.getBonusType());

            BonusCalculation calculation = calculationMapper.selectOne(queryWrapper);
            if (calculation != null) {
                calculation.setBonusAmount(bonusPayment.getBonusAmount());
                calculation.setCalculationRule(bonusPayment.getCalculationRule());
                calculation.setCalculator(bonusPayment.getCalculator());
                calculation.setCalculationTime(bonusPayment.getCalculationTime());

                calculationMapper.updateById(calculation);
            }
        } catch (Exception e) {
            log.error("更新奖金核算记录失败，paymentId: {}", bonusPayment.getPaymentId(), e);
        }
    }

    /**
     * 更新核算记录状态
     *
     * @param employeeNo 工号
     * @param bonusType  奖金类型
     * @param status     状态 (0待审核 1已审核 2已发放)
     */
    private void updateCalculationStatus(String employeeNo, String bonusType, String status) {
        try {
            BonusCalculationMapper calculationMapper = SpringUtils.getBean(BonusCalculationMapper.class);

            LambdaQueryWrapper<BonusCalculation> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(BonusCalculation::getEmployeeNo, employeeNo);
            queryWrapper.eq(BonusCalculation::getBonusType, bonusType);

            BonusCalculation calculation = calculationMapper.selectOne(queryWrapper);
            if (calculation != null) {
                calculation.setCalculationStatus(status);
                calculationMapper.updateById(calculation);
            }
        } catch (Exception e) {
            log.error("更新核算记录状态失败，employeeNo: {}, bonusType: {}", employeeNo, bonusType, e);
        }
    }

    /**
     * 根据工号获取员工姓名
     *
     * @param employeeNo 工号
     * @return 员工姓名
     */
    private String getEmployeeNameByNo(String employeeNo) {
        try {
            // 这里需要根据实际的员工表结构来查询员工姓名
            // 暂时返回工号，实际项目中需要查询员工表
            return "员工-" + employeeNo;
        } catch (Exception e) {
            log.warn("获取员工姓名失败，employeeNo: {}", employeeNo, e);
            return "未知员工";
        }
    }

    /**
     * 构建查询条件
     *
     * @param bo 奖金发放业务对象
     * @return 查询条件
     */
    private LambdaQueryWrapper<BonusPayment> buildQueryWrapper(BonusPaymentBo bo) {
        LambdaQueryWrapper<BonusPayment> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getTenantId()), BonusPayment::getTenantId, bo.getTenantId());
        lqw.eq(StringUtils.isNotBlank(bo.getEmployeeNo()), BonusPayment::getEmployeeNo, bo.getEmployeeNo());
        lqw.eq(StringUtils.isNotBlank(bo.getBonusType()), BonusPayment::getBonusType, bo.getBonusType());
        lqw.eq(bo.getPaymentTime() != null, BonusPayment::getPaymentTime, bo.getPaymentTime());
        lqw.eq(StringUtils.isNotBlank(bo.getPaymentStatus()), BonusPayment::getPaymentStatus, bo.getPaymentStatus());
        lqw.eq(StringUtils.isNotBlank(bo.getReceiveStatus()), BonusPayment::getReceiveStatus, bo.getReceiveStatus());
        return lqw;
    }

    /**
     * 保存前的数据校验
     *
     * @param entity 实体类数据
     */
    private void validEntityBeforeSave(BonusPayment entity) {
        // 校验员工工号是否存在
        if (StringUtils.isBlank(entity.getEmployeeNo())) {
            throw new RuntimeException("员工工号不能为空");
        }

        // 校验奖金金额必须大于0
        if (entity.getBonusAmount() == null || entity.getBonusAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new RuntimeException("奖金金额必须大于0");
        }

        // 校验金额合理性（阈值校验）
        validBonusAmount(entity.getBonusAmount());

        // 校验发放时间不能为空
        if (entity.getPaymentTime() == null) {
            throw new RuntimeException("发放时间不能为空");
        }

        // 校验状态合法性
        if (StringUtils.isNotBlank(entity.getPaymentStatus()) &&
                !"0".equals(entity.getPaymentStatus()) && !"1".equals(entity.getPaymentStatus())) {
            throw new RuntimeException("发放状态只能是0(未发放)或1(已发放)");
        }

        if (StringUtils.isNotBlank(entity.getReceiveStatus()) &&
                !"0".equals(entity.getReceiveStatus()) && !"1".equals(entity.getReceiveStatus())) {
            throw new RuntimeException("领取状态只能是0(未领取)或1(已领取)");
        }

        // 校验奖金类型不能为空
        if (StringUtils.isBlank(entity.getBonusType())) {
            throw new RuntimeException("奖金类型不能为空");
        }

        // 校验状态变更的合法性
        validStatusTransition(entity);
    }

    /**
     * 校验状态变更的合法性
     *
     * @param entity 奖金发放实体
     */
    private void validStatusTransition(BonusPayment entity) {
        // 如果是更新操作，需要校验状态变更是否合法
        if (entity.getPaymentId() != null) {
            BonusPayment oldEntity = baseMapper.selectById(entity.getPaymentId());
            if (oldEntity != null) {
                String oldStatus = oldEntity.getPaymentStatus();
                String newStatus = entity.getPaymentStatus();

                // 发放状态只能从未发放(0)变更为已发放(1)，不能回退
                if ("1".equals(oldStatus) && "0".equals(newStatus)) {
                    throw new RuntimeException("状态变更不合法：已发放状态不能回退为未发放");
                }
            }
        }
    }

    /**
     * 导入数据校验
     *
     * @param importVo 导入数据对象
     * @return 是否校验通过
     */
    private boolean validImportData(BonusImportVo importVo) {
        // 校验工号
        if (StringUtils.isBlank(importVo.getEmployeeNo())) {
            return false;
        }

        // 校验奖金类型
        if (StringUtils.isBlank(importVo.getBonusType())) {
            return false;
        }

        // 校验奖金金额
        if (importVo.getBonusAmount() == null || importVo.getBonusAmount().compareTo(BigDecimal.ZERO) <= 0) {
            return false;
        }

        // 校验金额合理性（阈值校验）
        try {
            validBonusAmount(importVo.getBonusAmount());
        } catch (Exception e) {
            return false;
        }

        // 校验发放时间
        if (importVo.getPaymentTime() == null) {
            return false;
        }

        return true;
    }

    /**
     * 校验奖金金额合理性
     *
     * @param bonusAmount 奖金金额
     */
    private void validBonusAmount(BigDecimal bonusAmount) {
        // 设置金额阈值，例如单笔奖金不能超过10万元
        BigDecimal maxAmount = new BigDecimal("100000");
        if (bonusAmount.compareTo(maxAmount) > 0) {
            throw new RuntimeException("奖金金额超出阈值，单笔奖金不能超过" + maxAmount.toString());
        }

        // 可以添加更多校验规则，例如：
        // 1. 不能为负数（已在基础校验中处理）
        // 2. 不能有过多小数位
        if (bonusAmount.scale() > 2) {
            throw new RuntimeException("奖金金额小数位不能超过2位");
        }
    }
}
